package edu.hawaii.duedates;

import java.util.Calendar;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.ArrayList;
import java.util.Properties;
import java.util.Timer;
import java.util.TimerTask;
import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
import edu.hawaii.duedates.lender.HawaiiStatePublicLibrary;
import edu.hawaii.duedates.lender.Lender;
import edu.hawaii.duedates.lender.LogInException;
import edu.hawaii.duedates.lender.ParseItemException;
import edu.hawaii.duedates.lender.UhManoaLibrary;

/**
 * New DueDates class in consideration to be used.
 * 
 * @author Daniel Tian
 *
 */
public class DueDates extends TimerTask {
  private final List<Lender> lenderList;
  private final Console console;
  private String output;
  private Double wakeupValue = 0.0;
  
  /**
   * Constructor.
   * 
   * @param args Array of string arguments.
   */
  public DueDates(String[] args) {
    lenderList = new ArrayList<Lender>();
    this.console = new Console(this, args);
    console.parseArguments();
  }
  
  /**
   * Get console method.
   * 
   * @return this.console
   */
  public Console getConsole() {
    return this.console;
  }

  /**
   * Required for extension of TimerTask class that runs on wake up.
   */
  public void run() {
    if (this.getWakeupValue() > 0) {
      this.lenderList.clear();
      this.console.parseArguments();  // Reset and update list.
    }
    if (!this.getConsole().isErrorOccurred()) {
      this.output = this.getConsole().printBorrowedItems();
      if (this.getConsole().useConsoleOutput()) {
        System.out.println(this.output);
      }
      if (this.getConsole().useEmailOutput()) {
        this.emailResults(this.getConsole().getEmailAddress(),
            this.getConsole().getSmtpServer());
      }
    }
  }
  
  /**
   * Main method. Entry point for DueDates application.
   * 
   * @param args List of arguments from the command line.
   */
  public static void main(String[] args) {
    DueDates dueDates = new DueDates(args);
    if (dueDates.getWakeupValue() > 0) {
      Timer timer = new Timer();
      Calendar now = Calendar.getInstance();
      timer.schedule(dueDates, now.getTime(), 
          Long.valueOf(Math.round(1000 * 3600 * 24 * dueDates.getWakeupValue())));
    }
    else {
      dueDates.run();
    }
  }
  
  /**
   * Creates a new instance of UhManoaLibrary.
   * 
   * @param idNumber ID number of the user.
   * @param lastName Last name of the user.
   */
  public void createUhManoaLibrary(String idNumber, String lastName) {
    UhManoaLibrary lender = new UhManoaLibrary();
    this.createLender(lender, idNumber, lastName);
  }
  
  /**
   * Creates a new instance of HawaiiStatePublicLibrary.
   * 
   * @param idNumber ID number of the user.
   * @param last4PhoneDigits Last 4 digits of the user's phone number.
   */
  public void createHawaiiStatePublicLibrary(String idNumber, String last4PhoneDigits) {
    HawaiiStatePublicLibrary lender = new HawaiiStatePublicLibrary();
    this.createLender(lender, idNumber, last4PhoneDigits);
  }
  
  /**
   * Sets the login fields for the lender and adds it to the lender list.
   * 
   * @param lender Lender object.
   * @param field1 First field required for login, usually the ID.
   * @param field2 Second field required for login, usually the password.
   */
  private void createLender(Lender lender, String field1, String field2) {
    lender.setLoginFields(field1, field2);
    this.lenderList.add(lender);
  }
  
  /**
   * Logs in all the lenders in the lender list.
   *    * @throws LogInException Thrown if the login failed.
   */
  public void logInAllLenders() throws LogInException {
    for (Lender lender : lenderList) {
      try {
        lender.logIn();
      }
      catch (LogInException e) {
        throw new LogInException(lender.getLenderName() + " - " + e.getMessage(), e);
      }
    }
  }
  
  /**
   * Queries all the lenders in the lender list for the borrowed books.
   * 
   * @throws LogInException Thrown if the login failed.
   * @throws ParseItemException Thrown if an item couldn't be parsed successfully.
   */
  public void queryAllLenders() throws LogInException, ParseItemException {
    for (Lender lender : lenderList) {
      try {
        lender.queryBorrowedItems();
      }
      catch (LogInException e) {
        throw new LogInException(lender.getLenderName() + " - " + e.getMessage(), e);
      }
      catch (ParseItemException e) {
        throw new ParseItemException(lender.getLenderName() + " - " + e.getMessage(), e);
      }
    }
  }
  
  /**
   * Sorts the lender list by lender name.
   */
  public void sortByLenderName() {
    Collections.sort(lenderList);
  }
  
  /**
   * Sorts the lender list's borrowed items by due date.
   */
  public void sortByDueDate() {
    for (Lender lender : lenderList) {
      Collections.sort(lender.getItemList());
    }
  }
  
  /**
   * Returns the list of lenders.
   * 
   * @return The list of lenders. 
   */
  public List<Lender> getLenderList() {
    return this.lenderList;
  }
  
  /**
   * Sends an email with the results of this due date's queries to the indicated address.
   * 
   * @param emailAddress To address.
   * @param smtpServer SMTP server.
   */
  public void emailResults(String emailAddress, String smtpServer) {
    if (this.output == null) {
      System.out.println("Nothing to send.");
    }
    try {
      Properties property = new Properties();
      property.put("mail.smtp.host", smtpServer);
      Session session = Session.getInstance(property);
      Message message = new MimeMessage(session);
      InternetAddress from = new InternetAddress("duedates-orange-discuss@googlegroups.com");
      InternetAddress to = new InternetAddress(emailAddress);
      message.setFrom(from);
      message.setRecipient(Message.RecipientType.TO, to);
      message.setSubject("DueDates results");
      message.setSentDate(new Date());
      message.setText(this.output);
      Transport.send(message);
      System.out.println("Email sent.");
    }
    catch (MessagingException e) {
      e.printStackTrace();
      System.out.println("Error sending e-mail.");
    }
  }

  /**
   * Output string getter.
   * 
   * @return The query output.
   */
  public String getOutput() {
    return this.output;
  }
  
  /**
   * Output string setter.
   * 
   * @param output The output string to be set as.
   */
  public void setOutput(String output) {
    this.output = output;
  }

  /**
   * Set wakeupValue.
   * 
   * @param wakeupValue The wakeupValue to set.
   */
  public void setWakeupValue(Double wakeupValue) {
    this.wakeupValue = wakeupValue;
  }

  /**
   * Get wakeupValue.
   * 
   * @return The wakeupValue.
   */
  public Double getWakeupValue() {
    return wakeupValue;
  }
}
